home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
- /*
- shadows.c - Draw a scene with shadow-volume shadow calculation
- using VGX graphics hardware stencil planes.
-
- Tim Heidmann, Silicon Graphics
-
- Created June 1, 1988
- Last Edit November 25, 1991
- */
-
- #include <stdio.h>
- #include <gl.h>
- #include <gl/image.h>
- #include <device.h>
- #include <math.h>
- #include <string.h>
- #include "trackball.h"
- #include "shadows.h"
- #include "glo_obj.h"
- #include "vect.h"
-
- #define PI (3.1415926535)
- #define TWOPI (6.283185308)
- #define RAD2DEG (180.0/PI)
- #define MAXOBJS 10
- #define MAXLITES 8
- #define STENZERO 128
- #define SPACING 1.2
- #define SHADOWLENGTH 100.0
- #define NEARCLIP 0.25
- #define FARCLIP 30.0
- #define WINHEIGHT 0.1
-
-
- /* Scene description global variables */
- float obj_posn[MAXOBJS][3];
- float obj_scale[MAXOBJS];
- Matrix obj_rotMatrix[MAXOBJS];
- int obj_litMaterial[MAXOBJS];
- int obj_shadowMaterial[MAXOBJS];
- int obj_highMaterial[MAXOBJS];
- int obj_texture[MAXOBJS];
- glo_ObjPtr obj_drawlist[MAXOBJS];
- PolyDataPtr obj_data[MAXOBJS];
- int nObjects = 0;
-
- float light_posn[MAXLITES][3];
- float jitter_light_posn[MAXLITES][3];
- float jitter_light_range[MAXLITES][3];
- int nLights = 0;
-
- /* Viewing, window, and interaction parameters */
- float eyex[] = { 0.0, 0.0, 9.0};
- float gazex[] = { 0.0, 0.0, 0.0};
- Matrix scene_rotMatrix;
- float scene_spin[4] = {0.0, 0.0, 0.0, 1.0};
- float scene_posn[3] = {0.0, 0.0, 0.0};
- int windowParmsSet;
- float windowParms[6];
- float viewWindow[3] = {WINHEIGHT, NEARCLIP, FARCLIP};
- Screencoord lox,hix,loy,hiy;
- int win_ox, win_oy, win_sx, win_sy;
- float nmx, nmy, omx, omy;
- Boolean acFlag = FALSE;
- int acCount = -1;
- int acFrames = 64;
-
- /* Constants to support texture mapping - property arrays, texgen parameters */
- float tev_val[] = {TV_NULL};
- float tex_val[] =
- {TX_MINFILTER, TX_BILINEAR, TX_MAGFILTER, TX_BILINEAR, TX_NULL};
- float tex_sparams[] = {1.0, 0.0, 0.0, 0.0};
- float tex_tparams[] = {0.0, 0.0, 1.0, 0.0};
- float subdiv_params[] = {10000.0, 0.0, 0.0};
-
- /* Program execution flags and modes */
- char *sceneFileName;
- char *imageFileName;
- enum {showScene, showVolumes, showMask, showShadows} showMode=showScene;
- int showVolSilEdges;
- int showVolShadowEdges;
- int showVolObjects;
- long CmdMenu;
- Boolean canZBuffer, canStencil, canAccum;
- int stencilZero;
-
- /* What colors to use for what stencil values in showMask display mode */
- /* In/Out: 1/1 2/2 3/3 1/0 2/1 3/2 2/0, 0/0 is clear */
- int maskValue[] = {0x5, 0xa, 0xf, 0x4, 0x9, 0xe, 0x8};
- int maskColor[] = {
- 0x00ff00ff, /* 1/1 - in == out, magenta */
- 0x00ff00ff, /* 2/2 */
- 0x00ff00ff, /* 3/3 */
- 0x00ff0000, /* 1/0 - in == out+1, blue */
- 0x00ff0000, /* 2/1 */
- 0x00ff0000, /* 3/2 */
- 0x00c0c000, /* 2/0 - in == out+2, blue-green */
- };
- int nMasks = (sizeof(maskValue)/sizeof(int));
-
- Matrix IdentMat = {
- 1.0, 0.0, 0.0, 0.0,
- 0.0, 1.0, 0.0, 0.0,
- 0.0, 0.0, 1.0, 0.0,
- 0.0, 0.0, 0.0, 1.0
- };
-
-
- /* Forward definitions */
- void
- ParseArgs(int c, char *v[]);
- int
- GetTBPosition(int state);
- void
- UpdateSceneRot();
- void
- AccumNext();
- void
- DoCmdMenu(Boolean *quitFlag, Boolean *redrawFlag);
- void
- GetNextSilEdge(EdgePtr edgeList, int thisEdge, int thisSide,
- int *pNextEdge, int *pNextSide);
-
-
-
- main(int argc, char *argv[])
- {
- /* These flags control the operation of the main loop:
- done - When true, bust out of the loop and exit;
- refresh - need to redraw the scene;
- okayToBlock - nothing spinning, being moved, or accumulating -
- can wait for event;
- buttonState - combination of LEFT & MID mouse buttons -
- !=0 means scene is being moved.
- spinning - The last movement had some rotation, which continues
- when the mouse button is released.
- acFlag - We want to jitter lights and accumulate when scene not moving.
- acCount - >0: more to accumulate, ==0: done, <0: clear and accumulate.
- */
- Boolean done, refresh, okayToBlock, spinning;
- short val, i, j;
- int buttonState;
- char buf[100];
-
- ParseArgs(argc, argv);
- InitGFX();
- InitDevices();
- InitMenus();
- InitScene();
- qenter(REDRAW,0);
-
- buttonState = GetButtonState();
- spinning = FALSE;
- for (done = FALSE;;) {
- /* Go get all the events or maybe sit and wait for one */
- while(qtest() || okayToBlock) {
- switch(qread(&val)) {
- case REDRAW:
- ShapeWindow(); refresh = TRUE; break;
- case ESCKEY:
- case QKEY:
- case WINQUIT:
- done = TRUE; break;
- case LEFTMOUSE:
- case MIDDLEMOUSE:
- buttonState = GetButtonState(); break;
- case RIGHTMOUSE:
- if (val) DoCmdMenu(&done, &refresh); break;
- default:
- break;
- }
- okayToBlock = FALSE;
- }
-
- /* Now handle all the events */
- if (done) break;
-
- if (buttonState != 0) {
- spinning = GetTBPosition(buttonState); refresh = TRUE;
- }
- if (spinning) {
- UpdateSceneRot(); refresh = TRUE;
- }
- if (refresh) {
- RepositionLights();
- DrawFrame(); swapbuffers(); acCount = -1; refresh = FALSE;
- } else if (acFlag && showMode == showShadows)
- AccumNext();
-
- okayToBlock = (buttonState != 0) ? FALSE :
- spinning ? FALSE :
- (showMode == showShadows && acFlag && acCount != 0) ? FALSE : TRUE;
-
- if (okayToBlock && imageFileName != NULL) {
- sprintf(buf, "scrsave %s %d %d %d %d", imageFileName,
- lox, hix, loy, hiy);
- system(buf);
- break;
- }
-
- }
-
- FinishDevices();
- FinishGFX();
- }
-
-
- int
- GetButtonState() {
- omx = 2.0 * (getvaluator(MOUSEX) - win_ox) / win_sx - 1.0;
- omy = 2.0 * (getvaluator(MOUSEY) - win_oy) / win_sy - 1.0;
- return getbutton(LEFTMOUSE) << 1 | getbutton(MIDDLEMOUSE);
- }
-
- int
- GetTBPosition(int state) {
- float delta[3];
- int spinning;
-
- nmx = 2.0 * (getvaluator(MOUSEX) - win_ox) / win_sx - 1.0;
- nmy = 2.0 * (getvaluator(MOUSEY) - win_oy) / win_sy - 1.0;
- spinning = FALSE;
-
- switch (state) {
- case 1: /* Middle mouse - rotate */
- trackball(scene_spin, omx, omy, nmx, nmy);
- /* No spin is scene_spin == {0,0,0,1};
- vlength looks at just 1st 3 elements */
- spinning = vlength(scene_spin) > 0.00001;
- break;
- case 2: /* Left mouse - translate */
- vset(delta, nmx - omx, nmy - omy, 0.0);
- vadd(scene_posn, delta, scene_posn);
- break;
- case 3: /* Left & Middle - Track in/out */
- scene_posn[2] += nmy - omy;
- break;
- default:
- break;
- }
- omx = nmx;
- omy = nmy;
-
- return spinning;
- }
-
- void
- UpdateSceneRot() {
- Matrix spinMatrix;
-
- build_rotmatrix(spinMatrix, scene_spin);
- vmultmatrix(scene_rotMatrix, spinMatrix, scene_rotMatrix);
- }
-
- void
- AccumNext() {
- int nDone;
-
- /* Reset accumulation buffer and count if necessary */
- if (acCount == 0) return;
- if (acCount < 0) {
- acbuf(AC_CLEAR, 0.0);
- acCount = acFrames;
- }
-
- /* Accumulate another frame */
- JitterLights();
- DrawFrame();
- readsource(SRC_BACK);
- acbuf(AC_ACCUMULATE, 1.0);
- acCount--;
-
- /* Copy accumulation buffer back to display whenever
- - count reaches specified number (acFrames)
- - count is a power of two, >=4 (4,8,16,32...) */
- nDone = acFrames - acCount;
- if (acCount == 0 || ((nDone&(nDone-1)) == 0 && nDone >= 4)) {
- acbuf(AC_RETURN, 1.0/nDone);
- swapbuffers();
- }
- }
-
- void
- ParseArgs(int c, char *v[]) {
- char *callName;
- int i, iLeft, iRight, iBottom, iTop;
-
- sceneFileName = NULL;
- imageFileName = NULL;
- showMode = showScene;
- showVolSilEdges = TRUE;
- showVolShadowEdges = FALSE;
- showVolObjects = TRUE;
- windowParmsSet = FALSE;
-
- callName = v[0];
- for (c--, v++; c > 0; c--, v++) {
- if (v[0][0] == '-')
- switch (v[0][1]) {
- case 'p': /* Window position */
- iLeft = atoi(v[1]);
- iRight = atoi(v[2]);
- iBottom = atoi(v[3]);
- iTop = atoi(v[4]);
- prefposition(iLeft, iRight, iBottom, iTop);
- c -= 4; v += 4;
- break;
- case 'w': /* Window perspective parameters */
- for (i=0; i<6; i++)
- if (sscanf(v[1 + i], "%f", windowParms + i) != 1)
- BadCall(callName);
- windowParmsSet = TRUE;
- c -= 6; v += 6;
- break;
- case 'o': /* Save scene as .rgb file */
- imageFileName = v[1];
- v += 1; c -= 1;
- break;
- case 'j': /* Jitter frames */
- acFlag = TRUE;
- acFrames = atoi(v[1]);
- v++; c--;
- break;
- case 'b': /* Block until this program finishes */
- foreground(); break;
- case 'n': /* Normal Scene */
- showMode = showScene; break;
- case 'v': /* Show volumes */
- showMode = showVolumes; break;
- case 'm': /* Show mask */
- showMode = showMask; break;
- case 's': /* Show shadows */
- showMode = showShadows; break;
- case 'e': /* Show silhouette edges */
- showVolSilEdges = TRUE; break;
- case 'f': /* Don't show silhouette edges */
- showVolSilEdges = FALSE; break;
- case 'E': /* Show shadow volume edges */
- showVolShadowEdges = TRUE; break;
- case 'F': /* Don't show shadow volume edges */
- showVolShadowEdges = FALSE; break;
- case 'd': /* Hide objects */
- showVolObjects = FALSE; break;
- default:
- BadCall(callName);
- break;
- }
- else
- /* Parse the scene file name */
- sceneFileName = v[0];
- }
-
- /* Check for valid operations */
- canZBuffer = getgdesc(GD_BITS_NORM_ZBUFFER) > 0;
- canStencil = getgdesc(GD_BITS_STENCIL) > 0;
- canAccum = getgdesc(GD_BITS_ACBUF_HW) > 0;
-
- if (acFlag && !canAccum) {
- fprintf(stderr,
- "This machine has no accumulation buffer, which is required\n");
- fprintf(stderr,
- "to compute soft shadows by jittering the light sources.\n");
- acFlag = FALSE;
- }
- if (!canStencil) {
- fprintf(stderr,
- "This machine has no stencil planes, which are required for\n");
- fprintf(stderr,
- "shadow calculation.\n");
- acFlag = FALSE;
- }
- if (!canZBuffer) {
- fprintf(stderr,
- "This program requires a z-buffer to run.\n");
- exit(1);
- }
- }
-
- BadCall(char *callName) {
- fprintf(stderr, "usage: %s [options] [<scene filename>]\n", callName);
- fprintf(stderr, " -p <left right bottom top> Window position\n");
- fprintf(stderr, " -w <left right bottom top near far>\n");
- fprintf(stderr, " Window parameters\n");
- fprintf(stderr, " -o <filename> Output to .rgb file\n");
- fprintf(stderr, " -j <frames> Max Jitter Frames\n");
- fprintf(stderr, " -b Block until program finishes\n");
- fprintf(stderr, " The following modes are exclusive:\n");
- fprintf(stderr, " -n Show normal scene\n");
- fprintf(stderr, " -v Show volumes\n");
- fprintf(stderr, " -m Show mask\n");
- fprintf(stderr, " -s Show shadows\n");
- fprintf(stderr, " The following flags apply to volume mode only:\n");
- fprintf(stderr, " -e Show silhouette edges\n");
- fprintf(stderr, " -f Don't show silhouette edges\n");
- fprintf(stderr, " -E Show shadow volume edges\n");
- fprintf(stderr, " -F Don't show shadow volume edges\n");
- fprintf(stderr, " -d Hide objects\n");
- exit(1);
- }
-
-
- InitGFX()
- {
- #ifdef DEBUG
- foreground();
- #endif
- winopen("Shadow Volumes");
- RGBmode();
- doublebuffer();
- stensize(8);
- acsize(16);
- stencilZero = STENZERO;
- gconfig();
- cpack(0x00000000);
- clear();
- swapbuffers();
-
- zbuffer(TRUE);
- lsetdepth(0x000100, 0x7fffff);
- subpixel(TRUE);
- mmode(MVIEWING);
-
- tevdef(1, 0, tev_val);
- tevbind(TV_ENV0, 1);
- texgen(TX_S, TG_LINEAR, tex_sparams);
- texgen(TX_T, TG_LINEAR, tex_tparams);
- texgen(TX_S, TG_ON, NULL);
- texgen(TX_T, TG_ON, NULL);
- }
-
- FinishGFX() {
- gexit();
- }
-
- InitDevices() {
- if (imageFileName == NULL) {
- /* If we are saving an image, don't allow interaction */
- qdevice(LEFTMOUSE);
- qdevice(MIDDLEMOUSE);
- qdevice(RIGHTMOUSE);
- }
- qdevice(ESCKEY);
- qdevice(QKEY);
- }
-
- FinishDevices() {
- unqdevice(LEFTMOUSE);
- unqdevice(MIDDLEMOUSE);
- unqdevice(RIGHTMOUSE);
- unqdevice(ESCKEY);
- unqdevice(QKEY);
- }
-
- InitMenus() {
- CmdMenu = defpup("");
- MakeCmdMenu();
- }
-
- MakeCmdMenu() {
- freepup(CmdMenu);
- CmdMenu=defpup("Shadow Scene %t");
- addtopup(CmdMenu, "Show Objects Only %x3");
- addtopup(CmdMenu, "Show Volumes %x1");
- if (canStencil) {
- addtopup(CmdMenu, "Show Mask %x2");
- addtopup(CmdMenu, "Show Shadows %x4 %l");
- }
- if (canAccum)
- if (acFlag)
- addtopup(CmdMenu, "Turn Soft Shadows Off %x5 %l");
- else
- addtopup(CmdMenu, "Turn Soft Shadows On %x5 %l");
- addtopup(CmdMenu, "Quit %x0");
- }
-
-
- void
- DoCmdMenu(Boolean *quitFlag, Boolean *redrawFlag)
- {
- *quitFlag = FALSE;
- *redrawFlag = TRUE;
- switch (dopup(CmdMenu)) {
- case 0: *quitFlag = TRUE; break;
- case 1: showMode=showVolumes; break;
- case 2: showMode=showMask; break;
- case 3: showMode=showScene; break;
- case 4: showMode=showShadows; break;
- case 5: acFlag = !acFlag; MakeCmdMenu(); break;
- default: break;
- }
- }
-
-
- ShapeWindow()
- {
- /* Reshape window, set up perspective and camera transform.
- Provide an undistorted view given any window aspect ratio.
- viewWindow[0]: height of near plane window,
- viewWindow[1]: near clipping plane,
- viewWindow[2]: far clipping plane */
- long xorg, yorg;
- float aspect;
-
- reshapeviewport();
- getviewport(&lox,&hix,&loy,&hiy);
- getorigin(&win_ox, &win_oy);
- lox += win_ox; hix += win_ox;
- loy += win_oy; hiy += win_oy;
- win_sx = hix - lox;
- win_sy = hiy - loy;
- aspect = ((float) win_sx)/win_sy;
- mmode(MPROJECTION);
- if (windowParmsSet)
- window(windowParms[0], windowParms[1],
- windowParms[2], windowParms[3],
- windowParms[4], windowParms[5]);
- else
- if (aspect > 1.0)
- window(-viewWindow[0]*aspect,viewWindow[0]*aspect,
- -viewWindow[0],viewWindow[0],
- viewWindow[1], viewWindow[2]);
- else
- window(-viewWindow[0],viewWindow[0],
- -viewWindow[0]/aspect,viewWindow[0]/aspect,
- viewWindow[1], viewWindow[2]);
-
- lookat(eyex[0], eyex[1], eyex[2], gazex[0], gazex[1], gazex[2], 0);
- mmode(MVIEWING);
- loadmatrix(IdentMat);
- }
-
-
- DrawFrame() {
- int i, j;
-
- czclear(0x00000000,0x7fffff);
-
- /* Draw the Scene */
- zbuffer(TRUE);
- zwritemask(0xffffffff);
- wmpack(0xffffffff);
- blendfunction(BF_ONE, BF_ZERO);
- for (i=0; i<nLights; i++) lmbind(LIGHT0+i, i+1);
- stencilZero = STENZERO;
-
- switch (showMode) {
- case showScene:
- DrawObjects(obj_litMaterial);
- return;
- case showVolumes:
- if (showVolObjects) DrawObjects(obj_litMaterial);
- break;
- case showMask:
- stencilZero = 0;
- DrawObjects(obj_litMaterial);
- break;
- case showShadows:
- DrawObjects(obj_shadowMaterial);
- break;
- default: ;
- }
-
- /* Draw the shadow volumes */
- lmbind(MATERIAL, 0);
- zwritemask(0x00000000);
-
- switch (showMode) {
- case showVolumes:
- /* To draw the volumes: */
- wmpack(0xffffffff);
- blendfunction(BF_SA, BF_MSA);
- cpack(0x18ffffff);
- DrawShadows(0);
-
- /* Now the silhouette edges */
- if (showVolSilEdges) {
- cpack(0x0000ffff);
- blendfunction(BF_ONE, BF_ZERO);
- DrawSilEdges();
- }
- break;
-
- case showMask:
- /* Build the stencil shadow mattes: */
- sclear(stencilZero);
- wmpack(0x00000000);
- DrawShadows(0);
-
- /* Draw the mask */
- wmpack(0xffffffff);
- zbuffer(FALSE);
- for (i=0; i<nMasks; i++) {
- stencil(TRUE, maskValue[i], SF_EQUAL, 0xff,
- ST_KEEP, ST_KEEP, ST_KEEP);
- DrawSquare(maskColor[i]);
- }
- stencil(FALSE, 0, 0, 0, 0, 0, 0);
- break;
-
- case showShadows:
- for (i=0; i<nLights; i++) {
- /* Set the lights */
- for (j=0; j<nLights; j++) lmbind(LIGHT0+j, (j==i) ? j+1 : 0);
-
- /* Build the stencil shadow mattes: */
- sclear(stencilZero);
- wmpack(0x00000000);
- DrawShadows(i);
-
- /* Draw shadowed elements */
- wmpack(0xffffffff);
- stencil(TRUE, stencilZero, SF_EQUAL, 0xff,
- ST_KEEP, ST_KEEP, ST_KEEP);
- blendfunction(BF_ONE, BF_ONE);
- DrawObjects(obj_highMaterial);
- }
- stencil(FALSE, 0, 0, 0, 0, 0, 0);
- break;
- }
- }
-
-
- DrawObjects(int objMaterial[])
- {
- /* Draw all objects in this scene */
- int i;
- pushmatrix();
- translate(scene_posn[0], scene_posn[1], scene_posn[2]);
- multmatrix(scene_rotMatrix);
- for (i=0; i<nObjects; i++) {
- pushmatrix();
- translate(obj_posn[i][0], obj_posn[i][1], obj_posn[i][2]);
- multmatrix(obj_rotMatrix[i]);
- scale(obj_scale[i], obj_scale[i], obj_scale[i]);
- lmbind(MATERIAL, objMaterial[i]);
- if (obj_texture[i] > 0) {
- texbind(TX_TEXTURE_0, obj_texture[i]);
- scrsubdivide(SS_DEPTH, subdiv_params);
- glo_DrawObj(obj_drawlist[i]);
- texbind(TX_TEXTURE_0, 0);
- scrsubdivide(SS_OFF, NULL);
- } else
- glo_DrawObj(obj_drawlist[i]);
- popmatrix();
- }
- popmatrix();
- }
-
-
- DrawShadows(int lighti) {
- float x, y, z;
- int i;
- Matrix myMatrix;
-
- for (i=0; i<nObjects; i++) {
- pushmatrix();
- translate(scene_posn[0], scene_posn[1], scene_posn[2]);
- multmatrix(scene_rotMatrix);
- translate(obj_posn[i][0], obj_posn[i][1], obj_posn[i][2]);
- multmatrix(obj_rotMatrix[i]);
- scale(obj_scale[i], obj_scale[i], obj_scale[i]);
- getmatrix(myMatrix);
- popmatrix();
- DrawSilhouettes(obj_drawlist[i], obj_data[i], myMatrix,
- jitter_light_posn[lighti]);
- }
- }
-
-
- DrawSquare(long color)
- {
- Matrix saveViewMatrix, saveProjMatrix;
-
- getmatrix(saveViewMatrix);
- mmode(MPROJECTION);
- getmatrix(saveProjMatrix);
- mmode(MVIEWING);
-
- cpack(color);
- ortho2(-1.0, 1.0, -1.0, 1.0);
- rectf(-1.0, -1.0, 1.0, 1.0);
-
- mmode(MPROJECTION);
- loadmatrix(saveProjMatrix);
- mmode(MVIEWING);
- loadmatrix(saveViewMatrix);
- }
-
-
- DrawSilhouettes(myOP, myPDP, xformMatrix, lightx)
- glo_ObjPtr myOP;
- PolyDataPtr myPDP;
- Matrix xformMatrix;
- float lightx[];
- {
- int i, iEdge, thisEdge, firstEdge, thisSide, iFace;
- Matrix rotOnlyMat;
- float xformedNormal[3], lightToEye[3];
- float lightToV1[3], lightToLastV1[3];
- float shadowFaceNormal[3];
- float worldV1[3], worldV2[3], lastV1[3], lastV2[3];
- EdgePtr pEdge;
- Boolean ingoing, lastIngoing, onceThrough;
-
- /* Get a rotation-only version of modeling transform for transforming
- normals */
- vmatcopy(xformMatrix, rotOnlyMat);
- for (i=0; i<3; i++) rotOnlyMat[3][i] = 0.0;
-
- /* Mark each face for lightedness */
- for (iFace = 0; iFace < myPDP->nFaces; iFace++) {
- vtransform(myPDP->faces[iFace].n, rotOnlyMat, xformedNormal);
- myPDP->faces[iFace].lit = vdot(xformedNormal, lightx) > 0.0;
- }
-
- /* Evaluate and clear per-edge flags */
- for (iEdge = 0, pEdge = myPDP->edges; iEdge < myPDP->nEdges;
- iEdge++, pEdge++) {
- pEdge->silhouetteFlag =
- (pEdge->e[1].face < 0 ||
- myPDP->faces[pEdge->e[0].face].lit !=
- myPDP->faces[pEdge->e[1].face].lit);
- pEdge->markedFlag = FALSE;
- }
-
- /* For each silhouette edge, if it has not been projected yet,
- trace a complete loop of silhouette edges, projecting shadow volumes */
- /* iEdge is main edge list index; thisEdge, firstEdge, and pEdge trace
- silhouette loops */
- vsub(eyex, lightx, lightToEye);
- for (iEdge = 0; iEdge<myPDP->nEdges; iEdge++) {
-
- /* If this is not a silhouette edge, or if we've projected it, skip */
- pEdge = myPDP->edges + iEdge;
- if (!pEdge->silhouetteFlag || pEdge->markedFlag) continue;
-
- firstEdge = thisEdge = iEdge;
- thisSide = 0;
- onceThrough = FALSE;
- lastIngoing = -1;
- if (showMode == showShadows) bgnqstrip();
-
- for (;;) {
- /* Transform first edge vertex to world coordinates */
- vtransform(myOP->t[pEdge->e[thisSide].vertex],
- xformMatrix, worldV1);
-
- /* Project first edge vertex away from light to get a new vertex. */
- vsub(worldV1, lightx, lightToV1);
- vscale(lightToV1, SHADOWLENGTH/vlength(lightToV1));
- vadd(worldV1, lightToV1, worldV2);
-
- if (onceThrough) {
- /* Is this shadow face going into or out of shadow? */
- vcross(lightToLastV1, lightToV1, shadowFaceNormal);
- ingoing = vdot(shadowFaceNormal, lightToEye) > 0;
- if (!myPDP->faces[pEdge->e[thisSide].face].lit)
- ingoing = !ingoing;
- }
-
- /* Set up and draw next 2 vertices of this shadow face quad */
- if (onceThrough)
- if (showMode == showShadows) {
- if (lastIngoing != ingoing) {
- endqstrip();
- stencil(TRUE, 0, SF_ALWAYS, 0xff, ST_KEEP, ST_KEEP,
- ingoing?ST_INCR:ST_DECR);
- bgnqstrip();
- v3f(lastV1); v3f(lastV2);
- lastIngoing = ingoing;
- }
- v3f(worldV1); v3f(worldV2);
- }
- else if (showMode == showMask) {
- for (i=0; i<(ingoing?4:1); i++) {
- stencil(TRUE, 0, SF_ALWAYS, 0xff, ST_KEEP, ST_KEEP,
- ST_INCR);
- bgnpolygon();
- v3f(lastV1); v3f(lastV2); v3f(worldV2); v3f(worldV1);
- endpolygon();
- }
- }
- else if (showMode == showVolumes) {
- bgnpolygon();
- v3f(lastV1); v3f(lastV2); v3f(worldV2); v3f(worldV1);
- endpolygon();
- if (showVolShadowEdges) {
- /* Draw the edges of the shadow faces for clarity */
- bgnclosedline();
- v3f(lastV1); v3f(lastV2); v3f(worldV2); v3f(worldV1);
- endclosedline();
- }
- }
-
- /* Exit if we've completed a full loop of sihouettes */
- if (thisEdge == firstEdge && onceThrough) break;
-
- /* Update loop indices, pointers, and values */
- pEdge->markedFlag = TRUE;
- vcopy(lightToV1, lightToLastV1);
- vcopy(worldV1, lastV1);
- vcopy(worldV2, lastV2);
- GetNextSilEdge(myPDP->edges, thisEdge, thisSide,
- &thisEdge, &thisSide);
- pEdge = myPDP->edges + thisEdge;
- onceThrough = TRUE;
- }
-
- if (showMode == showShadows) endqstrip();
- }
- }
-
-
- void
- GetNextSilEdge(EdgePtr edgeList, int thisEdge, int thisSide,
- int *pNextEdge, int *pNextSide) {
- int nextEdge, nextSide;
-
- for (;;) {
- nextEdge = edgeList[thisEdge].e[thisSide].nextEdge;
- nextSide = edgeList[thisEdge].e[thisSide].nextSide;
-
- /* If the next edge around this polygon is a silhouette, we're done */
- if (edgeList[nextEdge].silhouetteFlag) break;
-
- /* Otherwise, go to the next polygon and check the next edge. */
- thisEdge = nextEdge;
- thisSide = 1 - nextSide;
- }
- *pNextEdge = nextEdge;
- *pNextSide = nextSide;
- }
-
-
- DrawSilEdges() {
- /* For each object, transform and draw all silhouette edges, based
- on lit flags set by DrawSilhouettes. Yellow solid lines for
- visible edges, dotted lines for those that fail z-buffer test.
- Fudge the lsetdepth to help keep visible lines from breaking up. */
-
- int iObj, iEdge;
- EdgePtr thisEdge;
-
- lsetdepth(0x000000, 0x7ffeff);
- deflinestyle(1, 0xf0f0);
-
- for (iObj=0; iObj<nObjects; iObj++) {
- pushmatrix();
- translate(scene_posn[0], scene_posn[1], scene_posn[2]);
- multmatrix(scene_rotMatrix);
- translate(obj_posn[iObj][0], obj_posn[iObj][1], obj_posn[iObj][2]);
- multmatrix(obj_rotMatrix[iObj]);
- scale(obj_scale[iObj], obj_scale[iObj], obj_scale[iObj]);
-
- for (iEdge = 0, thisEdge = obj_data[iObj]->edges;
- iEdge<obj_data[iObj]->nEdges; iEdge++, thisEdge++) {
-
- /* If this is a silhouette edge, draw it. */
- if (thisEdge->silhouetteFlag) {
-
- /* Draw hidden, dashed lines first */
- setlinestyle(1);
- zfunction(ZF_GREATER);
- bgnline();
- v3f(obj_drawlist[iObj]->t[thisEdge->e[0].vertex]);
- v3f(obj_drawlist[iObj]->t[thisEdge->e[1].vertex]);
- endline();
-
- /* Then visible, solid lines next */
- setlinestyle(0);
- zfunction(ZF_LEQUAL);
- bgnline();
- v3f(obj_drawlist[iObj]->t[thisEdge->e[0].vertex]);
- v3f(obj_drawlist[iObj]->t[thisEdge->e[1].vertex]);
- endline();
- }
- }
- popmatrix();
- }
- lsetdepth(0x000100, 0x7fffff);
- }
-
- int
- JitterLights() {
- int i, j;
-
- for (i=0; i<nLights; i++)
- for (j=0; j<3; j++)
- jitter_light_posn[i][j] = light_posn[i][j] +
- ((random() & 0xffff)/32768.0 - 1.0) *
- jitter_light_range[i][j];
- }
-
- int
- RepositionLights() {
- int i, j;
-
- for (i=0; i<nLights; i++)
- for (j=0; j<3; j++)
- jitter_light_posn[i][j] = light_posn[i][j];
- }
-